import logging
from django.core.exceptions import ObjectDoesNotExist
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework.authentication import TokenAuthentication
from rest_framework.parsers import JSONParser
from rest_framework.views import APIView
from api_test.common.api_response import JsonResponse
from api_test.common.common import record_dynamic
from api_test.common.statuscode_loadfile import add_status_code
from api_test.models import Project, ApiStatusCode
from api_test.serializers import ProjectSerializer, ApiStatusCodeSerializer, ApiStatusCodeDeserializer
from api_test.common.decorator import catch_exception
from api_test.common_exception.exceptions import ParamsMissedException, ParamsTypeErrorException, \
    NoPerMissionException, ObjectIsDeletedException, ObjectNotFoundException

logger = logging.getLogger(__name__)  # 这里使用 __name__ 动态搜索定义的 logger 配置，这里有一个层次关系的知识点。


class StatusCode(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @swagger_auto_schema(manual_parameters=[
        openapi.Parameter(name="project_id", in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER, description="项目id"),
        openapi.Parameter(name="code", in_=openapi.IN_QUERY, type=openapi.TYPE_INTEGER, description="状态码"),
    ])
    @catch_exception
    def get(self, request):
        """
        接口状态码
        """
        project_id = request.GET.get("project_id")
        code = request.GET.get("code")
        # 校验参数
        if not project_id:
            raise ParamsMissedException('project_id')
        if not project_id.isdecimal():
            raise ParamsTypeErrorException('project_id')
        # 验证项目是否存在
        try:
            pro_data = Project.objects.get(id=project_id)
        except ObjectDoesNotExist:
            raise ObjectDoesNotExist
        # 序列化结果
        pro_data = ProjectSerializer(pro_data)
        # 校验项目状态
        if not pro_data.data["status"]:
            raise ObjectIsDeletedException('项目' + str(project_id))
        # 查找项目下所有接口状态码信息，并按id排序，序列化结果
        obi = ApiStatusCode.objects.filter(project=project_id, status=True)
        if code:
            obi = obi.filter(code=code)
        obi.order_by("id")
        serialize = ApiStatusCodeSerializer(obi, many=True)
        return JsonResponse(data=serialize.data, code="999999", msg="成功!")


class AddStatusCode(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @catch_exception
    def parameter_check(self, data):
        """
        校验参数
        """
        # 必传参数
        for param in ['project_id', 'codeList']:
            if not data.get(param):
                raise ParamsMissedException(param)
        # 校验project_id类型为int
        if not isinstance(data["project_id"], int):
            raise ParamsTypeErrorException('project_id')
        if not isinstance(data['codeList'], list):
            raise ParamsTypeErrorException('codeList')
        if isinstance(data["codeList"], list):
            for code in data['codeList']:
                if isinstance(code['code'], str):
                    code['code'] = int(code['code'])

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['project_id', 'codeList'],
        properties={
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="项目id"),
            'codeList': openapi.Schema(type=openapi.TYPE_ARRAY,
                                       items=openapi.Schema(type=openapi.TYPE_OBJECT,
                                                            required=['code'],
                                                            properties={'code': openapi.Schema(
                                                                type=openapi.TYPE_INTEGER),
                                                                        'description': openapi.Schema(
                                                                            type=openapi.TYPE_STRING)},
                                                            description="新增状态码列表"))
        },
    ))
    @catch_exception
    def post(self, request):
        """
        新增接口状态码
        """
        data = JSONParser().parse(request)
        result = self.parameter_check(data)
        if result:
            return result
        # 校验项目状态
        try:
            obj = Project.objects.get(id=data["project_id"])
            if not request.user.is_superuser and obj.user.is_superuser:
                raise NoPerMissionException(obj.user.name)
        except ObjectDoesNotExist:
            raise ObjectNotFoundException('项目' + str(data.get['project_id']))
        pro_data = ProjectSerializer(obj)
        if not pro_data.data["status"]:
            raise ObjectIsDeletedException('项目' + str(data['project_id']))
        request_code_list = [code.get('code') for code in data.get('codeList')]
        codes = ApiStatusCode.objects.filter(project=data['project_id'],
                                             code__in=request_code_list, status=True)
        repeat_list = [code.get('code') for code in codes.values()]
        if codes.count() > 0:
            return JsonResponse(code="999997", msg=f"请求存在重复code列表{repeat_list}!")
        else:
            # 反序列化
            serializer = ApiStatusCodeDeserializer(data=data.get('codeList'), many=True)
            # 校验反序列化正确，正确则保存，外键为project
            if serializer.is_valid():
                serializer.save(project=obj)
            else:
                return JsonResponse(code="999998", msg="失败!")
            # 新增接口操作
            status_code = request_code_list[0] if len(request_code_list) == 1 else request_code_list
            record_dynamic(project=serializer.data[0].get("project_id"),
                           _type="添加", operationObject="接口状态码", user=request.user.pk,
                           data=f"新增接口状态码'{status_code}'")
            return JsonResponse(data={
                "codeList": [obj.get('code') for obj in serializer.validated_data]
            }, code="999999", msg="成功!")


class UpdateStatusCode(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @catch_exception
    def parameter_check(self, data):
        """
        校验参数
        project_id: int
        id: int,
        code: int
        """
        # 必传参数 name
        for param in ['project_id', 'id', 'code']:
            if not data.get(param):
                raise ParamsMissedException(param)
        # 校验project_id, id类型为int
        for param in ['project_id', 'id']:
            if not isinstance(data.get(param), int):
                raise ParamsTypeErrorException(param)
        if isinstance(data["code"], str):
            data["code"] = int(data["code"])

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['id', 'project_id', 'code'],
        properties={
            'id': openapi.Schema(type=openapi.TYPE_INTEGER, description="状态码id"),
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="项目id"),
            'code': openapi.Schema(type=openapi.TYPE_STRING, description="状态码"),
            'description': openapi.Schema(type=openapi.TYPE_STRING, description="描述"),
        },
    ))
    @catch_exception
    def post(self, request):
        """
        修改接口状态码
        """
        data = JSONParser().parse(request)
        result = self.parameter_check(data)
        if result:
            return result
        try:
            pro_data = Project.objects.get(id=data['project_id'])
            if not request.user.is_superuser and pro_data.user.is_superuser:
                raise NoPerMissionException(request.user)
        except ObjectDoesNotExist:
            raise ObjectNotFoundException('项目' + str(data['project_id']))
        pro_data = ProjectSerializer(pro_data)
        if not pro_data.data['status']:
            raise ObjectIsDeletedException('项目' + str(data['project_id']))
        try:
            obj = ApiStatusCode.objects.get(id=data["id"], project=data["project_id"])
        except ObjectDoesNotExist:
            return JsonResponse(code="999991", msg="code不存在!")
        serializer = ApiStatusCodeDeserializer(data=data)
        if serializer.is_valid():
            serializer.update(instance=obj, validated_data=data)
        else:
            return JsonResponse(code="999998", msg="失败!")
        record_dynamic(project=serializer.data.get("project_id"),
                       _type="修改", operationObject="接口状态码", user=request.user.pk,
                       data="修改接口状态码“%s”" % data["code"])
        return JsonResponse(code="999999", msg="成功!")


class DelStatusCode(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @catch_exception
    def parameter_check(self, data):
        """
        校验参数
        project_id: int
        ids: list
        """
        for param in ['project_id', 'ids']:
            if not data.get(param):
                raise ParamsMissedException(param)
        if not isinstance(data["ids"], list):
            raise ParamsTypeErrorException('ids')
        if not isinstance(data['project_id'], int):
            raise ParamsTypeErrorException('project_id')
        for i in data["ids"]:
            if not isinstance(i, int):
                raise ParamsTypeErrorException('ids')

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['project_id', 'ids'],
        properties={
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="项目id"),
            'ids': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Items(type=openapi.TYPE_INTEGER),
                                  description="待删除待接口状态码 id列表"),
        },
    ))
    def post(self, request):
        """
        删除(禁用)接口状态码
        """
        data = JSONParser().parse(request)
        result = self.parameter_check(data)
        if result:
            return result
        try:
            pro_data = Project.objects.get(id=data["project_id"])
            if not request.user.is_superuser and pro_data.user.is_superuser:
                raise NoPerMissionException(request.user)
        except ObjectDoesNotExist:
            raise ObjectNotFoundException('项目' + str(data['project_id']))
        pro_data = ProjectSerializer(pro_data)
        if not pro_data.data["status"]:
            raise ObjectIsDeletedException('项目' + str(data['project_id']))
        # 根据项目id和模块 id查找，若存在则删除
        obj = ApiStatusCode.objects.filter(id__in=data.get('ids'), project=data.get('project_id'))
        if not obj:
            return JsonResponse(code="999995", msg="状态码不存在！")
        else:
            id_list = [i.code for i in obj]
            obj.update(status=False)
            record_dynamic(project=data['project_id'], _type="禁用", operationObject="接口状态码",
                           user=request.user.pk, data='禁用了接口状态码' + str(id_list))
            return JsonResponse(code="999999", msg="成功!", data={'codeList': id_list})


class ImportFileStatusCode(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = ()

    @catch_exception
    def parameter_check(self, data):
        """
        必传校验参数
        project_id: int
        file_id: int
        """
        for param in ['project_id', 'file_id']:
            if not data.get(param):
                raise ParamsMissedException(param)
        if not isinstance(data.get(param), int):
            raise ParamsTypeErrorException(param)

    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT,
        required=['project_id', 'file_id'],
        properties={
            'project_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="项目id"),
            'file_id': openapi.Schema(type=openapi.TYPE_INTEGER, description="文件id")
        },
    ))
    @catch_exception
    def post(self, request):
        """
        批量新增接口状态码
        """
        data = JSONParser().parse(request)
        self.parameter_check(data)
        # 校验项目状态
        obj = Project.objects.get(id=data['project_id'])
        if not request.user.is_superuser and obj.user.is_superuser:
            raise NoPerMissionException(request.user)
        pro_data = ProjectSerializer(obj)
        if not pro_data.data["status"]:
            raise ObjectIsDeletedException('项目' + str(data.get('project_id')))
        return add_status_code(data.get('project_id'), data.get('file_id'))
